package com.aplink.generic.util;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;

import com.aplink.generic.constant.ConfigParameter;

public class RotateImageView extends ImageView {
    private static final int ANIMATION_SPEED = 180 * 2;

    private static final int NONE = 0;
    @SuppressWarnings("unused")
    private static final String TAG = "RotateImageView";
    Path clipPath = null;
    int w, h;
    private int beginAngle = 0;

    private int deltaX = 0;
    private int deltaY = 0;
    private boolean editEnable = true;
    private boolean isMoved = false;
    private boolean isRequestEffect = false;
    private int lastDeltaX = 0;
    private int lastDeltaY = 0;
    // private ArrayList touchPoints = null;
    // private boolean isMultiTouch = false;
    // private int pathEffectPhase = 0;
    // private PointF centerPoint;
    private PointF lastPoint;
    private PointF lastPointPress;
    private final PointF lastPointPressSwipe = new PointF();
    private int lastTouchDegree = - 1;
    private long mAnimationEndTime = 0L;
    private long mAnimationStartTime = 0L;
    private final Matrix matrix = new Matrix();

    private final float maxScaleZoom = 5f;
    private boolean mClockwise = false;

    private int mCurrentDegree = 0;
    private final float minScale = 1f;

    private final int mode = NONE;
    private int mStartDegree = 0;

    private int mTargetDegree = 0;
    private float oldDist = 0.0f;

    private float origWidth, origHeight;

    private float saveScale = 1f;
    private float scaleFactor = 1.0f;
    private int scaleH = - 1;
    private int scaleW = - 1;
    private final boolean swipeEnable = false;

    private boolean useFitBoundMode = false;
    private boolean useRotateMode = true;
    private boolean useZoomMode = true;
    private float width, height;
    public boolean onLeftSide = false, onTopSide = false, onRightSide = false,
            onBottomSide = false;

    //
    // private CreateNewKard parentActivity = null;
    // private CreateNewKard parentActivitySwipe = null;

    public RotateImageView( Context context ) {
        super( context );
        super.setClickable( true );
        this.initialize( context );
    }

    public RotateImageView( Context context, AttributeSet attrs ) {
        super( context, attrs );
        this.initialize( context );
        super.setClickable( true );
    }

    public RotateImageView( Context context, AttributeSet attrs, int defStyle ) {
        super( context, attrs, defStyle );
        this.initialize( context );
        super.setClickable( true );
    }

    public RotateImageView( Context context, int defStyle ) {
        super( context, null, defStyle );
        this.initialize( context );
        super.setClickable( true );
    }

    private int getDeltaX( MotionEvent event ) {
        return Math.round( event.getX( 0 ) - this.lastPointPress.x );
    }

    private int getDeltaY( MotionEvent event ) {
        return Math.round( event.getY( 0 ) - this.lastPointPress.y );
    }

    private void initialize( Context context ) {
        // touchPoints = new ArrayList();
        this.lastPoint = new PointF();
        this.lastPoint.set( - 1F, - 1F );
        this.lastPointPress = new PointF();
        this.lastPointPress.set( - 1F, - 1F );
        this.editEnable = true;
    }

    private int rotation( MotionEvent event ) {
        final double delta_x = event.getX( 0 ) - event.getX( 1 );
        final double delta_y = event.getY( 0 ) - event.getY( 1 );

        if ( delta_x == 0 ) {
            return 0;
        } else {
            double radians;
            // if (delta_x > 0){
            radians = Math.atan2( delta_y, delta_x );
            return (int) Math.round( Math.toDegrees( radians ) );
            // }
            // else{
            // radians = Math.atan2(delta_y, -delta_x);
            // return 180 + (int) Math.round(Math.toDegrees(radians));
            // }
        }
    }

    private float spacing( MotionEvent event ) {
        final float x = event.getX( 0 ) - event.getX( 1 );
        final float y = event.getY( 0 ) - event.getY( 1 );
        return (float) Math.sqrt( ( x * x ) + ( y * y ) );
    }

    @Override
    protected void onDraw( Canvas canvas ) {
        final Drawable drawable = this.getDrawable();
        if ( drawable == null ) {
            return;
        }
        if ( this.isRequestEffect && ( drawable != null ) ) {
            this.isRequestEffect = false;
        }

        final Rect bounds2 = drawable.getBounds();
        if ( this.scaleW == - 1 ) {
            this.scaleW = this.getWidth();
            this.scaleH = Math.round( ( this.getWidth() * ( bounds2.bottom + bounds2.top ) )
                    / ( bounds2.right + bounds2.left ) );
            if ( this.getHeight() > this.scaleH ) {
                this.scaleH = this.getHeight();
                this.scaleW = Math.round( ( this.getHeight()
                        * ( bounds2.right + bounds2.left ) )
                        / ( bounds2.bottom + bounds2.top ) );
            }
        }
        // end
        final Rect bounds = drawable.getBounds();

        this.w = Math.round( this.scaleFactor * ( bounds.left + this.scaleW ) );
        this.h = Math.round( this.scaleFactor * ( bounds.top + this.scaleH ) );
        drawable.setBounds( bounds.left, bounds.top, this.w, this.h );
        if ( ( this.w == 0 ) || ( this.h == 0 ) ) {
            return;
        }
        if ( this.mCurrentDegree != this.mTargetDegree ) {
            final long time = AnimationUtils.currentAnimationTimeMillis();
            if ( time < this.mAnimationEndTime ) {
                final int deltaTime = (int) ( time - this.mAnimationStartTime );
                int degree = this.mStartDegree
                        + ( ( ANIMATION_SPEED * ( this.mClockwise ? deltaTime
                        : - deltaTime ) ) / 1000 );
                degree = degree < 0 ? ( degree % 360 ) + 360 : degree % 360;
                this.mCurrentDegree = degree;
                this.invalidate();
            } else {
                this.mCurrentDegree = this.mTargetDegree;
            }
        }
        final int left = this.getPaddingLeft();
        final int top = this.getPaddingTop();
        final int right = this.getPaddingRight();
        final int bottom = this.getPaddingBottom();
        final int width = this.getWidth() - left - right;
        final int height = this.getHeight() - top - bottom;
        final int saveCount = canvas.getSaveCount();
        canvas.translate( left + ( width / 2 ) + this.deltaX, top + ( height / 2 ) + this.deltaY );
        canvas.rotate( - this.mCurrentDegree );
        canvas.translate( - this.w >> 1, - this.h >> 1 );
        drawable.draw( canvas );
        canvas.restoreToCount( saveCount );
    }

    protected void setDegree( int degree ) {
        // make sure in the range of [0, 359]
        degree = degree >= 0 ? degree % 360 : ( degree % 360 ) + 360;
        if ( degree == this.mTargetDegree ) {
            return;
        }

        this.mTargetDegree = degree;
        this.mStartDegree = this.mCurrentDegree;
        this.mAnimationStartTime = AnimationUtils.currentAnimationTimeMillis();

        int diff = this.mTargetDegree - this.mCurrentDegree;
        diff = diff >= 0 ? diff : 360 + diff; // make it in range [0, 359]

        // Make it in range [-179, 180]. That's the shorted distance between the
        // two angles
        diff = diff > 180 ? diff - 360 : diff;

        this.mClockwise = diff >= 0;
        this.mAnimationEndTime = this.mAnimationStartTime + ( ( Math.abs( diff ) * 1000 )
                / ANIMATION_SPEED );

        this.invalidate();
        System.out.println( ">>>> degree = " + degree );
        ConfigParameter.DEGREES_ROTATION = degree;
    }

    public void doRotate( int degree ) {
        this.setDegree( degree );
    }

    public int getImageHeight() {
        return this.scaleH;
    }

    // private void setPoints(MotionEvent event) {
    // touchPoints.clear();
    // int pointerIndex = 0;
    // for (int index = 0; index < event.getPointerCount(); index++) {
    // pointerIndex = event.getPointerId(index);
    // touchPoints.add(new PointF(event.getX(pointerIndex), event
    // .getY(pointerIndex)));
    // }
    //
    // }

    public int getImageWidth() {
        return this.scaleW;
    }

    public int getImageX() {
        return this.lastDeltaX != - 1 ? this.lastDeltaX : 0;
    }

    public int getImageY() {
        return this.lastDeltaY != - 1 ? this.lastDeltaY : 0;
    }

    public boolean getSwipeEnable() {
        return this.swipeEnable;
    }

    @Override
    public boolean onTouchEvent( MotionEvent event ) {
        super.onTouchEvent( event );
        if ( this.swipeEnable ) {
            final int action = event.getAction() & MotionEvent.ACTION_MASK;
            switch ( action ) {
                case MotionEvent.ACTION_DOWN:
                    this.lastPointPressSwipe.set( event.getX( 0 ), event.getY( 0 ) );
                    break;

                case MotionEvent.ACTION_POINTER_DOWN:
                    break;

                case MotionEvent.ACTION_POINTER_UP:
                    break;

                case MotionEvent.ACTION_UP:
                    if ( ( this.lastPointPressSwipe.x != - 1 ) && this.isMoved
                            && ( event.getX( 0 ) > ( this.lastPointPressSwipe.x - 30 ) ) ) {
                        // parentActivitySwipe.swipeLeftTemplate();
                    }
                    if ( ( this.lastPointPressSwipe.x != - 1 ) && this.isMoved
                            && ( event.getX( 0 ) < ( this.lastPointPressSwipe.x - 30 ) ) ) {
                        // parentActivitySwipe.swipeRightTemplate();
                    }
                    this.isMoved = false;
                    this.lastPointPressSwipe.set( - 1F, - 1F );
                    break;

                case MotionEvent.ACTION_MOVE:
                    this.isMoved = true;
                    break;
            }
            return true;
        }
        if ( ! this.editEnable ) {
            // TCuong 07 - 12 - 2012 return touch event for parent view - fix
            // bug KB not hide
            return false;
        }
        // end
        final int action = event.getAction() & MotionEvent.ACTION_MASK;
        try {
            switch ( action ) {
                case MotionEvent.ACTION_DOWN:
                    this.lastPointPress.set( event.getX( 0 ), event.getY( 0 ) );
                    this.invalidate();
                    break;

                case MotionEvent.ACTION_POINTER_DOWN:
                    // lastPointPress.set(event.getX(1), event.getY(1));
                    // isMultiTouch = true;
                    this.beginAngle = this.rotation( event );
                    this.oldDist = this.spacing( event );
                    this.invalidate();
                    break;

                case MotionEvent.ACTION_POINTER_UP:
                    // isMultiTouch = false;
                    this.lastPoint.set( - 1F, - 1F );
                    // lastDeltaX = deltaX;
                    // lastDeltaY = deltaY;
                    this.lastPointPress.set( - 1F, - 1F );
                    if ( this.scaleW > - 1 ) {
                        if ( this.scaleW > this.scaleH ) {
                            this.scaleW = Math.round( this.scaleFactor * this.scaleH ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleW ) :
                                    ( 10 * this.getWidth() )
                                            / this.getHeight();
                            this.scaleH = Math.round( this.scaleFactor * this.scaleH ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleH ) : 10;
                        } else {
                            this.scaleW = Math.round( this.scaleFactor * this.scaleW ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleW ) : 10;
                            this.scaleH = Math.round( this.scaleFactor * this.scaleW ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleH ) :
                                    ( 10 * this.getHeight() )
                                            / this.getWidth();
                        }
                    }
                    this.scaleFactor = 1.0F;
                    this.lastTouchDegree = this.mTargetDegree;
                    // lastDeltaX = deltaX;
                    // lastDeltaY = deltaY;
                    // lastTouchDegree += mCurrentDegree;
                    break;

                case MotionEvent.ACTION_UP:
                    // isMultiTouch = false;
                    this.lastPoint.set( - 1F, - 1F );
                    this.lastPointPress.set( - 1F, - 1F );
                    if ( this.scaleW > - 1 ) {
                        if ( this.scaleW > this.scaleH ) {
                            this.scaleW = Math.round( this.scaleFactor * this.scaleH ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleW ) :
                                    ( 10 * this.getWidth() )
                                            / this.getHeight();
                            this.scaleH = Math.round( this.scaleFactor * this.scaleH ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleH ) : 10;
                        } else {
                            this.scaleW = Math.round( this.scaleFactor * this.scaleW ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleW ) : 10;
                            this.scaleH = Math.round( this.scaleFactor * this.scaleW ) > 10 ? Math
                                    .round( this.scaleFactor * this.scaleH ) :
                                    ( 10 * this.getHeight() )
                                            / this.getWidth();
                        }
                    }
                    this.scaleFactor = 1.0F;
                    this.lastTouchDegree = this.mTargetDegree;
                    this.lastDeltaX = this.deltaX;
                    this.lastDeltaY = this.deltaY;
                    // lastTouchDegree += mCurrentDegree;
                    break;

                case MotionEvent.ACTION_MOVE:
                    if ( event.getPointerCount() > 1 ) {
                        if ( this.lastPoint.x == - 1F ) {
                            this.lastPoint.set( Math.abs( event.getX( 0 ) - event.getX( 1 ) ),
                                    Math.abs( event.getY( 0 ) - event.getY( 1 ) ) );
                        } else {
                            final int width = this.getWidth() - this.getPaddingLeft()
                                    - this.getPaddingRight();
                            final int height = this.getHeight() - this.getPaddingTop()
                                    - this.getPaddingBottom();
                            if ( ( ( ( ( width / 2 ) + Math.abs( this.deltaX ) ) <= ( Math
                                    .round( ( this.spacing( event )
                                            / this.oldDist )
                                            * ( this.getDrawable().getBounds().left +
                                            this.scaleW ) ) >> 1 ) ) && ( ( ( height
                                    / 2 ) + Math.abs( this.deltaY ) ) <= ( Math
                                    .round( ( this.spacing( event )
                                            / this.oldDist )
                                            * ( this.getDrawable().getBounds().top +
                                            this.scaleH ) ) >> 1 ) ) )
                                    || ! this.useFitBoundMode ) {
                                if ( this.useZoomMode ) {
                                    this.scaleFactor = this.spacing( event ) / this.oldDist;
                                }
                            }
                            // Log.d("debug degree lastTouchDegree", "  " +
                            // lastTouchDegree);
                            // Log.d("debug degree angle", "  " + (beginAngle -
                            // rotation(event)));
                            // Log.d("debug degree", "  " + (beginAngle -
                            // rotation(event) + lastTouchDegree));
                            // if(Math.abs(beginAngle - rotation(event)) < 180);
                            if ( this.useRotateMode ) {
                                this.setDegree( ( this.beginAngle - this.rotation( event ) )
                                        + this.lastTouchDegree );// > 10 ?
                                // rotation(event)
                                // + mCurrentDegree
                                // :
                                // mCurrentDegree);
                            }
                        }
                    } else {
                        if ( this.lastPointPress.x == - 1F ) {
                            this.lastPointPress.set( event.getX( 0 ), event.getY( 0 ) );
                        } else {
                            final int width = this.getWidth() - this.getPaddingLeft()
                                    - this.getPaddingRight();
                            final int height = this.getHeight() - this.getPaddingTop()
                                    - this.getPaddingBottom();
                            if ( ( ( ( width / 2 ) +
                                    Math.abs( this.getDeltaX( event ) + this.lastDeltaX ) ) <=
                                    ( this.w >> 1 ) )
                                    || ! this.useFitBoundMode ) {
                                this.deltaX = this.getDeltaX( event ) + this.lastDeltaX;
                            }
                            if ( ( ( ( height / 2 )
                                    + Math.abs( this.getDeltaY( event ) + this.lastDeltaY ) ) <=
                                    ( this.h >> 1 ) )
                                    || ! this.useFitBoundMode ) {
                                this.deltaY = this.getDeltaY( event ) + this.lastDeltaY;
                            }
                        }
                    }
                    this.invalidate();
                    break;
            }
        } catch ( final Exception exception ) {
        }
        return true;
    }

    public void onZoom( boolean zoomIn ) {

        float mScaleFactor = zoomIn ? 1.2f : 0.75f;

        final float origScale = this.saveScale;
        this.saveScale *= mScaleFactor;

        if ( this.saveScale > this.maxScaleZoom ) {
            this.saveScale = this.maxScaleZoom;
            mScaleFactor = this.maxScaleZoom / origScale;
        } else if ( this.saveScale < this.minScale ) {
            this.saveScale = this.minScale;
            mScaleFactor = this.minScale / origScale;
        }

        if ( ( ( this.origWidth * this.saveScale ) <= this.width ) ||
                ( ( this.origHeight * this.saveScale ) <= this.height ) ) {
            this.matrix.postScale( mScaleFactor, mScaleFactor, this.width / 2, this.height / 2 );
        } else {
            this.matrix.postScale( mScaleFactor, mScaleFactor, this.width / 2, this.height / 2 );
        }

        // matrix.getValues(m);
        // calcPadding();
        // checkAndSetTranslate(0, 0);

        // Log.w(TAG, "right : " + right);
        // Log.w(TAG, "width : " + width);
        // Log.w(TAG, "bottom : " + bottom);
        // Log.w(TAG, "height : " + height);
        // Log.w(TAG, "redundantXSpace : " + redundantXSpace);
        // Log.w(TAG, "redundantYSpace : " + redundantYSpace);

        this.setImageMatrix( this.matrix );
        this.invalidate();
    }

    public boolean pagerCanScroll() {
        if ( this.mode != NONE ) {
            return false;
        }
        return this.saveScale == this.minScale;
    }

    public void reset() {
        // TCuong 10 - 12 - 2012 fix scale image input from camera or local file
        this.scaleW = - 1;// getWidth();
        this.scaleH = - 1;// getHeight();
        // end
        this.setDegree( 0 );
        this.scaleFactor = 1.0F;
        this.lastTouchDegree = 0;
        this.lastDeltaX = 0;
        this.lastDeltaY = 0;
        this.deltaX = 0;
        this.deltaY = 0;
    }

    public void setDefaultDrawing( boolean enable ) {
    }

    public void setEdit( boolean enable ) {
        this.editEnable = enable;
    }

    public void setImageHeight( int h ) {
        this.scaleH = h;
    }

    public void setImageWidth( int w ) {
        this.scaleW = w;
    }

    public void setImageX( int x ) {
        this.deltaX = x;
        this.lastDeltaX = x;
    }

    public void setImageY( int y ) {
        this.deltaY = y;
        this.lastDeltaY = y;
    }

    public void setUseFitBoundMode( boolean values ) {
        this.useFitBoundMode = values;
    }

    public void setUseRotateMode( boolean values ) {
        this.useRotateMode = values;
    }

    public void setUseRoundCorner( boolean values ) {
    }

    // public void requestEffect(CreateNewKard instance) {
    // isRequestEffect = true;
    // parentActivity = instance;
    // }

    public void setUseZoomMode( boolean values ) {
        this.useZoomMode = values;
    }

}